// -----------------------------------------------------------------------------
// Copyright (c) 2014-2023 All rights reserved
// -----------------------------------------------------------------------------
// Author : Ding Qingchen ding0489@foxmail.com
// File   : Decode.v
// Create : 2023-01-02 21:48:47
// Revise : 2023-01-02 21:48:47
// Editor : sublime text4, tab size (2)
// -----------------------------------------------------------------------------
module Decode(
  input clk,
  input rst,

  input enable,
  output ready,
//from fetch stage
  input [31:0] inst_i,
  input inst_valid,
  input [63:0] pc_i,
//from writeback stage
  input [4:0] waddr,
  input wen,
  input [63:0] wdata,

  output src1_valid,
  output src2_valid,
  output dest_valid,
//to execute stage
  output [63:0] pc_o,
  output [63:0] src1,
  output [63:0] src2,
  output [4:0] rs1,
  output [4:0] rs2,
  output [63:0] imm,
  output [4:0] dest,

  output [31:0] inst_o,

//to execute stage
  output op_valid_o,
//to arithmetic unit
  output [6:0] arithmetic_op,
//to logic unit
  output [21:0] logic_op,
//to branch unit
  output [7:0] branch_op,
//to load store unit
  output [7:0] load_op,
  output [3:0] store_op,
//to mul div unit
  output [4:0] mul_op,
  output [7:0] div_op,
//to CSR ctrl unit
  output [7:0] csr_op,
//fence op
  output [0:0] fence_op,
//other op
  output [1:0] other_op,
//unsupport op
  output [0:0] unsupport_op
);

  assign op_valid_o = inst_valid;
  assign inst_o = inst_i;
  wire [31:0] inst = inst_i;
  assign rs1 = {5{src1_valid}}&inst[19:15];
  assign rs2 = {5{src2_valid}}&inst[24:20];
  wire [4:0]  rd  /*verilator public_flat*/ = inst[11:7];

  wire [63:0] immI /*verilator public_flat*/ = {{52{inst[31]}},inst[31:20]};
  wire [63:0] immU /*verilator public_flat*/ = {{32{inst[31]}},inst[31:12],12'b0};
  wire [63:0] immS /*verilator public_flat*/ = {{52{inst[31]}},inst[31:25],inst[11:7]};
  wire [63:0] immJ /*verilator public_flat*/ = {{43{inst[31]}},inst[31],inst[19:12],inst[20],inst[30:21],1'b0};
  wire [63:0] immB /*verilator public_flat*/ = {{51{inst[31]}},inst[31],inst[7],inst[30:25],inst[11:8],1'b0};

  wire [6:0] opcode /*verilator public_flat*/ = inst[6:0];
  wire [2:0] funct3 /*verilator public_flat*/ = inst[14:12];
  wire [6:0] funct7 /*verilator public_flat*/ = inst[31:25];

  wire [63:0] rdata1;
  wire [63:0] rdata2;

  wire op_auipc     /*verilator public_flat*/ =     opcode == 7'b00101_11;                                                  //32'bxxxxxxx_xxxxx_xxxxx_xxx_xxxxx_00101_11;
  wire op_lui       /*verilator public_flat*/ =     opcode == 7'b01101_11;                                                  //32'bxxxxxxx_xxxxx_xxxxx_xxx_xxxxx_01101_11;
  wire op_addiw     /*verilator public_flat*/ =     opcode == 7'b00110_11 && funct3 == 3'b000;                              //32'bxxxxxxx_xxxxx_xxxxx_000_xxxxx_00110_11;
  wire op_addw      /*verilator public_flat*/ =     opcode == 7'b01110_11 && funct3 == 3'b000 && funct7 == 7'b0000000;      //32'b0000000_xxxxx_xxxxx_000_xxxxx_01110_11;
  wire op_ld        /*verilator public_flat*/ =     opcode == 7'b00000_11 && funct3 == 3'b011;                              //32'bxxxxxxx_xxxxx_xxxxx_011_xxxxx_00000_11;
  wire op_lwu       /*verilator public_flat*/ =     opcode == 7'b00000_11 && funct3 == 3'b110;                              //32'bxxxxxxx_xxxxx_xxxxx_110_xxxxx_00000_11;
  wire op_sd        /*verilator public_flat*/ =     opcode == 7'b01000_11 && funct3 == 3'b011;                              //32'bxxxxxxx_xxxxx_xxxxx_011_xxxxx_01000_11;
  wire op_slli      /*verilator public_flat*/ =     opcode == 7'b00100_11 && funct3 == 3'b001 && funct7[6:1] == 6'b000000;  //32'b000000x_xxxxx_xxxxx_001_xxxxx_00100_11;
  wire op_slliw     /*verilator public_flat*/ =     opcode == 7'b00110_11 && funct3 == 3'b001 && funct7[6:1] == 6'b000000;  //32'b000000x_xxxxx_xxxxx_001_xxxxx_00110_11;
  wire op_sllw      /*verilator public_flat*/ =     opcode == 7'b01110_11 && funct3 == 3'b001 && funct7 == 7'b0000000;      //32'b0000000_xxxxx_xxxxx_001_xxxxx_01110_11;
  wire op_srai      /*verilator public_flat*/ =     opcode == 7'b00100_11 && funct3 == 3'b101 && funct7[6:1] == 6'b010000;  //32'b010000x_xxxxx_xxxxx_101_xxxxx_00100_11;
  wire op_sraiw     /*verilator public_flat*/ =     opcode == 7'b00110_11 && funct3 == 3'b101 && funct7 == 7'b0100000;      //32'b0100000_xxxxx_xxxxx_101_xxxxx_00110_11;
  wire op_sraw      /*verilator public_flat*/ =     opcode == 7'b01110_11 && funct3 == 3'b101 && funct7 == 7'b0100000;      //32'b0100000_xxxxx_xxxxx_101_xxxxx_01110_11;
  wire op_srli      /*verilator public_flat*/ =     opcode == 7'b00100_11 && funct3 == 3'b101 && funct7[6:1] == 6'b000000;  //32'b000000x_xxxxx_xxxxx_101_xxxxx_00100_11;
  wire op_srliw     /*verilator public_flat*/ =     opcode == 7'b00110_11 && funct3 == 3'b101 && funct7[6:1] == 6'b000000;  //32'b000000x_xxxxx_xxxxx_101_xxxxx_00110_11;
  wire op_srlw      /*verilator public_flat*/ =     opcode == 7'b01110_11 && funct3 == 3'b101 && funct7 == 7'b0000000;      //32'b0000000_xxxxx_xxxxx_101_xxxxx_01110_11;
  wire op_subw      /*verilator public_flat*/ =     opcode == 7'b01110_11 && funct3 == 3'b000 && funct7 == 7'b0100000;      //32'b0100000_xxxxx_xxxxx_000_xxxxx_01110_11;
  wire op_DIVUW     /*verilator public_flat*/ =     opcode == 7'b01110_11 && funct3 == 3'b101 && funct7 == 7'b0000001;      //32'b0000001_xxxxx_xxxxx_101_xxxxx_01110_11;
  wire op_DIVW      /*verilator public_flat*/ =     opcode == 7'b01110_11 && funct3 == 3'b100 && funct7 == 7'b0000001;      //32'b0000001_xxxxx_xxxxx_100_xxxxx_01110_11;
  wire op_REMUW     /*verilator public_flat*/ =     opcode == 7'b01110_11 && funct3 == 3'b111 && funct7 == 7'b0000001;      //32'b0000001_xxxxx_xxxxx_111_xxxxx_01110_11;
  wire op_REMW      /*verilator public_flat*/ =     opcode == 7'b01110_11 && funct3 == 3'b110 && funct7 == 7'b0000001;      //32'b0000001_xxxxx_xxxxx_110_xxxxx_01110_11;
  wire op_MULW      /*verilator public_flat*/ =     opcode == 7'b01110_11 && funct3 == 3'b000 && funct7 == 7'b0000001;      //32'b0000001_xxxxx_xxxxx_000_xxxxx_01110_11;
  wire op_DIV       /*verilator public_flat*/ =     opcode == 7'b01100_11 && funct3 == 3'b100 && funct7 == 7'b0000001;      //32'b0000001_xxxxx_xxxxx_100_xxxxx_01100_11;
  wire op_DIVU      /*verilator public_flat*/ =     opcode == 7'b01100_11 && funct3 == 3'b101 && funct7 == 7'b0000001;      //32'b0000001_xxxxx_xxxxx_101_xxxxx_01100_11;
  wire op_REMU      /*verilator public_flat*/ =     opcode == 7'b01100_11 && funct3 == 3'b111 && funct7 == 7'b0000001;      //32'b0000001_xxxxx_xxxxx_111_xxxxx_01100_11;
  wire op_REM       /*verilator public_flat*/ =     opcode == 7'b01100_11 && funct3 == 3'b110 && funct7 == 7'b0000001;      //32'b0000001_xxxxx_xxxxx_110_xxxxx_01100_11;
  wire op_MUL       /*verilator public_flat*/ =     opcode == 7'b01100_11 && funct3 == 3'b000 && funct7 == 7'b0000001;      //32'b0000001_xxxxx_xxxxx_000_xxxxx_01100_11;
  wire op_MULH      /*verilator public_flat*/ =     opcode == 7'b01100_11 && funct3 == 3'b001 && funct7 == 7'b0000001;      //32'b0000001_xxxxx_xxxxx_001_xxxxx_01100_11;
  wire op_MULHSU    /*verilator public_flat*/ =     opcode == 7'b01100_11 && funct3 == 3'b010 && funct7 == 7'b0000001;      //32'b0000001_xxxxx_xxxxx_010_xxxxx_01100_11;
  wire op_MULHU     /*verilator public_flat*/ =     opcode == 7'b01100_11 && funct3 == 3'b011 && funct7 == 7'b0000001;      //32'b0000001_xxxxx_xxxxx_011_xxxxx_01100_11;
  wire op_add       /*verilator public_flat*/ =     opcode == 7'b01100_11 && funct3 == 3'b000 && funct7 == 7'b0000000;      //32'b0000000_xxxxx_xxxxx_000_xxxxx_01100_11;
  wire op_addi      /*verilator public_flat*/ =     opcode == 7'b00100_11 && funct3 == 3'b000;                              //32'bxxxxxxx_xxxxx_xxxxx_000_xxxxx_00100_11;
  wire op_and       /*verilator public_flat*/ =     opcode == 7'b01100_11 && funct3 == 3'b111 && funct7 == 7'b0000000;      //32'b0000000_xxxxx_xxxxx_111_xxxxx_01100_11;
  wire op_andi      /*verilator public_flat*/ =     opcode == 7'b00100_11 && funct3 == 3'b111;                              //32'bxxxxxxx_xxxxx_xxxxx_111_xxxxx_00100_11;
  wire op_beq       /*verilator public_flat*/ =     opcode == 7'b11000_11 && funct3 == 3'b000;                              //32'bxxxxxxx_xxxxx_xxxxx_000_xxxxx_11000_11;
  wire op_bge       /*verilator public_flat*/ =     opcode == 7'b11000_11 && funct3 == 3'b101;                              //32'bxxxxxxx_xxxxx_xxxxx_101_xxxxx_11000_11;
  wire op_bgeu      /*verilator public_flat*/ =     opcode == 7'b11000_11 && funct3 == 3'b111;                              //32'bxxxxxxx_xxxxx_xxxxx_111_xxxxx_11000_11;
  wire op_blt       /*verilator public_flat*/ =     opcode == 7'b11000_11 && funct3 == 3'b100;                              //32'bxxxxxxx_xxxxx_xxxxx_100_xxxxx_11000_11;
  wire op_bltu      /*verilator public_flat*/ =     opcode == 7'b11000_11 && funct3 == 3'b110;                              //32'bxxxxxxx_xxxxx_xxxxx_110_xxxxx_11000_11;
  wire op_bne       /*verilator public_flat*/ =     opcode == 7'b11000_11 && funct3 == 3'b001;                              //32'bxxxxxxx_xxxxx_xxxxx_001_xxxxx_11000_11;
  wire op_ecall     /*verilator public_flat*/ =     inst == 32'b0000000_00000_00000_000_00000_11100_11;
  wire op_fence     /*verilator public_flat*/ =     opcode == 7'b00011_11 && funct3 == 3'b000;                              //32'bxxxxxxx_xxxxx_xxxxx_000_xxxxx_00011_11;
  wire op_jal       /*verilator public_flat*/ =     opcode == 7'b11011_11;                                                  //32'bxxxxxxx_xxxxx_xxxxx_xxx_xxxxx_11011_11;
  wire op_jalr      /*verilator public_flat*/ =     opcode == 7'b11001_11 && funct3 == 3'b000;                              //32'bxxxxxxx_xxxxx_xxxxx_000_xxxxx_11001_11;
  wire op_lb        /*verilator public_flat*/ =     opcode == 7'b00000_11 && funct3 == 3'b000;                              //32'bxxxxxxx_xxxxx_xxxxx_000_xxxxx_00000_11;
  wire op_lbu       /*verilator public_flat*/ =     opcode == 7'b00000_11 && funct3 == 3'b100;                              //32'bxxxxxxx_xxxxx_xxxxx_100_xxxxx_00000_11;
  wire op_lh        /*verilator public_flat*/ =     opcode == 7'b00000_11 && funct3 == 3'b001;                              //32'bxxxxxxx_xxxxx_xxxxx_001_xxxxx_00000_11;
  wire op_lhu       /*verilator public_flat*/ =     opcode == 7'b00000_11 && funct3 == 3'b101;                              //32'bxxxxxxx_xxxxx_xxxxx_101_xxxxx_00000_11;
  wire op_lw        /*verilator public_flat*/ =     opcode == 7'b00000_11 && funct3 == 3'b010;                              //32'bxxxxxxx_xxxxx_xxxxx_010_xxxxx_00000_11;
  wire op_or        /*verilator public_flat*/ =     opcode == 7'b01100_11 && funct3 == 3'b110 && funct7 == 7'b0000000;      //32'b0000000_xxxxx_xxxxx_110_xxxxx_01100_11;
  wire op_ori       /*verilator public_flat*/ =     opcode == 7'b00100_11 && funct3 == 3'b110;                              //32'bxxxxxxx_xxxxx_xxxxx_110_xxxxx_00100_11;
  wire op_sb        /*verilator public_flat*/ =     opcode == 7'b01000_11 && funct3 == 3'b000;                              //32'bxxxxxxx_xxxxx_xxxxx_000_xxxxx_01000_11;
  wire op_sh        /*verilator public_flat*/ =     opcode == 7'b01000_11 && funct3 == 3'b001;                              //32'bxxxxxxx_xxxxx_xxxxx_001_xxxxx_01000_11;
  wire op_sw        /*verilator public_flat*/ =     opcode == 7'b01000_11 && funct3 == 3'b010;                              //32'bxxxxxxx_xxxxx_xxxxx_010_xxxxx_01000_11;
  wire op_sll       /*verilator public_flat*/ =     opcode == 7'b01100_11 && funct3 == 3'b001 && funct7 == 7'b0000000;      //32'b0000000_xxxxx_xxxxx_001_xxxxx_01100_11;
  wire op_slt       /*verilator public_flat*/ =     opcode == 7'b01100_11 && funct3 == 3'b010 && funct7 == 7'b0000000;      //32'b0000000_xxxxx_xxxxx_010_xxxxx_01100_11;
  wire op_slti      /*verilator public_flat*/ =     opcode == 7'b00100_11 && funct3 == 3'b010;                              //32'bxxxxxxx_xxxxx_xxxxx_010_xxxxx_00100_11;
  wire op_sltiu     /*verilator public_flat*/ =     opcode == 7'b00100_11 && funct3 == 3'b011;                              //32'bxxxxxxx_xxxxx_xxxxx_011_xxxxx_00100_11;
  wire op_sltu      /*verilator public_flat*/ =     opcode == 7'b01100_11 && funct3 == 3'b011;                              //32'bxxxxxxx_xxxxx_xxxxx_011_xxxxx_01100_11;
  wire op_sra       /*verilator public_flat*/ =     opcode == 7'b01100_11 && funct3 == 3'b101 && funct7 == 7'b0100000;      //32'b0100000_xxxxx_xxxxx_101_xxxxx_01100_11;
  wire op_srl       /*verilator public_flat*/ =     opcode == 7'b01100_11 && funct3 == 3'b101 && funct7 == 7'b0000000;      //32'b0000000_xxxxx_xxxxx_101_xxxxx_01100_11;
  wire op_sub       /*verilator public_flat*/ =     opcode == 7'b01100_11 && funct3 == 3'b000 && funct7 == 7'b0100000;      //32'b0100000_xxxxx_xxxxx_000_xxxxx_01100_11;
  wire op_xor       /*verilator public_flat*/ =     opcode == 7'b01100_11 && funct3 == 3'b100 && funct7 == 7'b0000000;      //32'b0000000_xxxxx_xxxxx_100_xxxxx_01100_11;
  wire op_xori      /*verilator public_flat*/ =     opcode == 7'b00100_11 && funct3 == 3'b100;                              //32'bxxxxxxx_xxxxx_xxxxx_100_xxxxx_00100_11;
  wire op_ebreak    /*verilator public_flat*/ =     inst == 32'b0000000_00001_00000_000_00000_11100_11;

  wire op_csrrw     /*verilator public_flat*/ =     opcode == 7'b11100_11 && funct3 == 3'b001;                              //32'bxxxxxxx_xxxxx_xxxxx_001_xxxxx_11100_11;
  wire op_csrrs     /*verilator public_flat*/ =     opcode == 7'b11100_11 && funct3 == 3'b010;                              //32'bxxxxxxx_xxxxx_xxxxx_010_xxxxx_11100_11;
  wire op_csrrc     /*verilator public_flat*/ =     opcode == 7'b11100_11 && funct3 == 3'b011;                              //32'bxxxxxxx_xxxxx_xxxxx_011_xxxxx_11100_11;
  wire op_csrrwi    /*verilator public_flat*/ =     opcode == 7'b11100_11 && funct3 == 3'b101;                              //32'bxxxxxxx_xxxxx_xxxxx_101_xxxxx_11100_11;
  wire op_csrrsi    /*verilator public_flat*/ =     opcode == 7'b11100_11 && funct3 == 3'b110;                              //32'bxxxxxxx_xxxxx_xxxxx_110_xxxxx_11100_11;
  wire op_csrrci    /*verilator public_flat*/ =     opcode == 7'b11100_11 && funct3 == 3'b111;                              //32'bxxxxxxx_xxxxx_xxxxx_111_xxxxx_11100_11;
  wire op_mert      /*verilator public_flat*/ =     inst == 32'b0011000_00010_00000_000_00000_11100_11;

  wire op_fence_i   /*verilator public_flat*/ =     inst == 32'b0000000_00000_00000_001_00000_00011_11;
//RV64I RV32I
  wire type_I /*verilator public_flat*/ = op_addiw|op_slli|op_slliw|op_srai|op_sraiw|op_srli|op_srliw|op_addi|op_andi|op_ori|op_slti|op_sltiu|op_xori|op_ld|op_lwu|op_jalr|op_lb|op_lbu|op_lh|op_lhu|op_lw|op_csrrw|op_csrrs|op_csrrc|op_csrrwi|op_csrrsi|op_csrrci;
  wire type_U /*verilator public_flat*/ = op_auipc|op_lui;
  wire type_S /*verilator public_flat*/ = op_sd|op_sb|op_sh|op_sw;
  wire type_J /*verilator public_flat*/ = op_jal;
  wire type_B /*verilator public_flat*/ = op_beq|op_bge|op_bgeu|op_blt|op_bltu|op_bne;
  wire type_R /*verilator public_flat*/ = op_addw|op_sllw|op_sraw|op_srlw|op_subw|op_add|op_and|op_or|op_sll|op_slt|op_sltu|op_sra|op_srl|op_sub|op_xor|op_DIVUW|op_DIVW|op_REMUW|op_REMW|op_DIV|op_DIVU|op_REMU|op_REM|op_MULW|op_MUL|op_MULH|op_MULHSU|op_MULHU;
  wire type_N /*verilator public_flat*/ = op_fence|op_ecall|op_ebreak;

  assign dest_valid = type_R|type_I|type_U|type_J;
  assign src1_valid = type_R|type_I|type_S|type_B;
  assign src2_valid = type_R|type_S|type_B;
  assign src1 = ({64{src1_valid}}&rdata1);
  assign src2 = ({64{src2_valid}}&rdata2);
  
  assign imm  = ({64{type_I}}&immI) |
                ({64{type_U}}&immU) |
                ({64{type_S}}&immS) |
                ({64{type_J}}&immJ) |
                ({64{type_B}}&immB) ;
  
  assign dest = rd;

  assign pc_o = pc_i;

  //7 ops
  assign arithmetic_op  = {op_addw,op_addiw,op_subw,op_add,op_addi,
                          op_sub,op_auipc};
  //22 ops
  assign logic_op       = {op_slli,op_slliw,op_sllw,op_srai,op_sraiw,
                          op_sraw,op_srli,op_srliw,op_srlw,op_and,
                          op_andi,op_or,op_ori,op_sll,op_slt,
                          op_slti,op_sltiu,op_sltu,op_sra,op_srl,
                          op_xor,op_xori};
  //8 ops
  assign branch_op      = {op_beq,op_bge,op_bgeu,op_blt,op_bltu,
                          op_bne,op_jal,op_jalr};
  //8 ops
  assign load_op        = {op_ld,op_lw,op_lwu,op_lh,op_lhu,
                          op_lb,op_lbu,op_lui};
  //4 ops
  assign store_op       = {op_sd,op_sw,op_sh,op_sb};
  //2 ops
  assign other_op       = {op_fence,op_ebreak};
  //8 ops
  assign div_op         = {op_DIVUW,op_DIVW,op_REMUW,op_REMW,op_DIV,op_DIVU,op_REMU,op_REM};
  //5 ops
  assign mul_op         = {op_MULW,op_MUL,op_MULH,op_MULHSU,op_MULHU};
  //8 ops
  assign csr_op         = {op_csrrw,op_csrrs,op_csrrc,op_csrrwi,op_csrrsi,op_csrrci,op_mert,op_ecall};
  //1 ops
  assign fence_op       = {op_fence_i};
  //1 ops
  assign unsupport_op   = ~{(|arithmetic_op)|(|logic_op)|(|branch_op)|(|load_op)|(|store_op)|(|mul_op)|(|div_op)|(|csr_op)|(|fence_op)|(|other_op)};
  RegisterFile #(
    .ADDR_WIDTH(5),
    .DATA_WIDTH(64)
        )
  inst_RegisterFile (
    .clk    (clk),
    .wdata  (wdata),
    .waddr  (waddr),
    .wen    (wen),
    .raddr1 (rs1),
    .raddr2 (rs2),
    .rdata1 (rdata1),
    .rdata2 (rdata2)
  );

  assign ready = enable;
endmodule
